package org.theSeed.fileContractLocImpl.contract.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.URLUtil;
import lombok.SneakyThrows;
import org.theSeed.base.pojo.sysEnum.SysCode;
import org.theSeed.base.utils.SeedStringUtil;
import org.theSeed.fileContract.contract.impl.FileContractAbstract;
import org.theSeed.fileContract.exp.FileUploadExp;
import org.theSeed.fileContract.pojo.dto.*;
import org.theSeed.fileContract.pojo.vo.*;
import org.theSeed.fileContract.utils.SeedFileConfigUtil;
import org.theSeed.fileContractLocImpl.pojo.prop.FileConfigLocProp;

import java.io.*;
import java.net.URLDecoder;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 文件本地上传
 */
public class FileContractLocImpl extends FileContractAbstract {
    private static String resourceIdParam = "resourceId";

    public FileContractLocImpl(String contractTypeInstance, FileConfigLocProp fileConfigLocProp,Long chipFileSize) {
        super(contractTypeInstance,fileConfigLocProp,chipFileSize);
    }

    @SneakyThrows
    @Override
    public InputStream getFile(SeedGetFileDto seedGetFileDto) {
        String fileLocPath = getFileConfigLocProp().getFileLocPath();
        File file = Paths.get(fileLocPath, seedGetFileDto.getResourceId()).toFile();
        if (!file.isFile())
            throw new FileUploadExp("文件不存在");
        return new FileInputStream(file);
    }

    @Override
    public SeedUploadFileVo uploadFile(SeedUploadFileDto seedUploadFileDto) {
        String resourceId = SeedFileConfigUtil.createWebParamResourceId(seedUploadFileDto.getRelativePath(), FileUtil.extName(seedUploadFileDto.getFileName()));
        uploadFile(resourceId,seedUploadFileDto.getIs());
        return SeedUploadFileVo.createSonUploadVo(resourceId,getFileUrl(resourceId));
    }

    @Override
    public SeedUploadFileVo updateFile(SeedUpdateFileDto seedUpdateFileDto) {
        uploadFile(seedUpdateFileDto.getResourceId(),seedUpdateFileDto.getIs());
        return new SeedUploadFileVo(seedUpdateFileDto.getResourceId(),getFileUrl(seedUpdateFileDto.getResourceId()));
    }

    @Override
    public SeedUploadFileVo deleteFile(SeedDeleteFileDto seedDeleteFileDto) {
        String fileLocPath = getFileConfigLocProp().getFileLocPath();
        File file = Paths.get(fileLocPath, URLDecoder.decode(seedDeleteFileDto.getResourceId())).toFile();
        if (file.exists())
            file.delete();
        return new SeedUploadFileVo(seedDeleteFileDto.getResourceId(),getFileUrl(seedDeleteFileDto.getResourceId()));
    }

    @Override
    public SeedUploadChipFileInitVo initUploadChipFile(SeedUploadChipFileInitDto seedUploadChipFileInitDto) {
        long chipFileSize = getChipFileSize() * 1024;
        String resourceId = SeedFileConfigUtil.createWebParamResourceId(seedUploadChipFileInitDto.getRelativePath(),FileUtil.extName(seedUploadChipFileInitDto.getFileName()));
        return new SeedUploadChipFileInitVo(resourceId,chipFileSize,Double.valueOf(Math.ceil((0d + seedUploadChipFileInitDto.getFileSize()) / chipFileSize)).intValue());
    }

    @Override
    public SeedUploadFileVo uploadChipFile(SeedUploadChipFileDto seedUploadChipFileDto,SeedUploadChipFileExtDto seedUploadChipFileExtDto) {
        String sonResourceId = SeedStringUtil.concatStr(URLDecoder.decode(seedUploadChipFileDto.getResourceId()), "_", seedUploadChipFileDto.getChipIndex());
        File chiFile = createFile(sonResourceId);
        //文件上传
        try (FileOutputStream fos = new FileOutputStream(chiFile)){
            IoUtil.copy(seedUploadChipFileDto.getIs(),fos);
            seedUploadChipFileDto.getIs().close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return new SeedUploadFileVo(seedUploadChipFileDto.getResourceId(),sonResourceId);
    }

    @Override
    public SeedUploadFileVo mergeChipFile(MergeChipFileDto mergeChipFileDto,SeedUploadChipFileExtDto seedUploadChipFileExtDto) {
        String resourceId = mergeChipFileDto.getResourceId();
        String resourcePath = URLDecoder.decode(resourceId);
        Long chipSize = seedUploadChipFileExtDto.getChipSize();
        if (ObjectUtil.isNull(chipSize)){
            throw new FileUploadExp("文件分片上传合并失败:chipSize不能为空");
        }
        String fileLocPath = ((FileConfigLocProp) (getFileConfigProp())).getFileLocPath();
        File rootFile = Paths.get(fileLocPath, resourcePath).toFile();
        createFile(resourcePath);
        byte[] content = new byte[8192];
        try (FileOutputStream rootFos = new FileOutputStream(rootFile);){
            for (Long l = 0l; l < chipSize; l++) {
                try(FileInputStream sonFis = new FileInputStream(Paths.get(fileLocPath, resourcePath+"_"+String.valueOf(l)).toFile());){
                    while (sonFis.read(content) != -1){
                        rootFos.write(content);
                        Arrays.fill(content, (byte)0);
                    }
                    rootFos.flush();
                }
            }
            rootFos.flush();
        }catch (Exception e){
            throw new FileUploadExp("文件分片上传合并失败:文件合并失败");
        }
        return new SeedUploadFileVo(resourceId,getFileUrl(resourceId));
    }

    @Override
    public CancleChipFileVo cancleChipFile(CancleChipFileDto cancleChipFileDto, SeedUploadChipFileExtDto seedUploadChipFileExtDto) {
        String resourceId = cancleChipFileDto.getResourceId();
        String resourcePath = URLDecoder.decode(resourceId);
        Long chipSize = seedUploadChipFileExtDto.getChipSize();
        File rootFile = createFile(resourcePath);
        rootFile.delete();
        for (Long l = 0l; l < chipSize; l++) {
            try {
                File tmpFile = createFile(SeedStringUtil.concatStr(resourcePath,"_",l));
                tmpFile.delete();
            } catch (IORuntimeException e) {
                throw new RuntimeException(e);
            }
        }

        return new CancleChipFileVo(resourceId);
    }

    @Override
    public String getContractType() {
        return "LOC";
    }

    @Override
    public Boolean jurgeInstance(String requestUrl) {
        FileConfigLocProp fileConfigProp = getFileConfigLocProp();
        UrlBuilder urlBuilder = UrlBuilder.of(requestUrl);
        return fileConfigProp.getFileHost().equals(urlBuilder.getHost()) && fileConfigProp.getPort().equals(urlBuilder.getPort()) && fileConfigProp.getFileUrlPrefix().equals(urlBuilder.getPath());
    }

    @Override
    public ResourceUrlDividVo sliceRequestUrl(String requestUrl) {
        FileConfigLocProp fileConfigProp = getFileConfigLocProp();
        UrlBuilder urlBuilder = UrlBuilder.of(requestUrl);
        if (fileConfigProp.getFileHost().equals(urlBuilder.getHost()) && fileConfigProp.getPort().equals(urlBuilder.getPort()) && fileConfigProp.getFileUrlPrefix().equals(urlBuilder.getPath())){
            CharSequence charSequence = urlBuilder.getQuery().get(resourceIdParam);
            return new ResourceUrlDividVo(this,charSequence.toString());
        }
        else{
            return new ResourceUrlDividVo(this,null);
        }
    }

    @Override
    public void destroy() {
    }

    /**
     * 文件保存
     * @param resourceId
     * @return
     */
    public File uploadFile(String resourceId,InputStream is){
        File file = createFile(URLDecoder.decode(resourceId));

        try (FileOutputStream fos = new FileOutputStream(file)){
            IoUtil.copy(is,fos);
            is.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return file;
    }

    /**
     * 创建文件,删除以前老文件
     * @return
     */
    public File createFile(String resourceId){
        String fileLocPath = getFileConfigLocProp().getFileLocPath();
        File file = Paths.get(fileLocPath, resourceId).toFile();
        //父目录操作
        File parentFile = file.getParentFile();
        parentFile.mkdirs();
        //子文件操作
        file.delete();
        try {
            file.createNewFile();
        } catch (IOException e) {
            throw new FileUploadExp("文件上传失败:本地文件删除失败");
        }
        return file;
    }

    /**
     * 获取文件地址
     * 路径地址规则{protocol}{fileHost}{fileUrlPrefix}
     * @return
     */
    public String getFileUrl(String resourceId){
        FileConfigLocProp fileConfigProp = getFileConfigLocProp();
        return URLUtil.decode(UrlBuilder.create()
                .setScheme(fileConfigProp.getProtocol())
                .setHost(fileConfigProp.getFileHost())
                .setPort(fileConfigProp.getPort())
                .addPath(fileConfigProp.getFileUrlPrefix())
                .addQuery(resourceIdParam, resourceId)
                .build());
    }

    /**
     * 获取本地配置
     * @return
     */
    public FileConfigLocProp getFileConfigLocProp(){
        return ((FileConfigLocProp) (getFileConfigProp()));
    }
}
